﻿using System;
using System.Collections.Generic;
using System.IO;
using ProphetsWay.myMedia.Core.Entities;
using ProphetsWay.Utilities;

namespace ProphetsWay.myMedia.Core
{
	/// <summary>
	/// Scans a Target directory for Files, returns a list of ProtoMedia
	/// Has two events to subscribe to, one is mandatory (*)
	/// DirectoryFinished
	/// ScanningFinished*
	/// </summary>
	public class DirectoryScanner : BackgroundWorkingClass
	{
		private string _root;

		private IList<ProtoMedia> _fileInfo;

		public DirectoryScanner() : this("") { }
		public DirectoryScanner(string scanningTargetRoot)
			: base("Directory Scanner")
		{
			Logger.Info(string.Format("Instantiating a new [DirectoryScanner] with a 'target root' of [{0}].", scanningTargetRoot));
			_root = scanningTargetRoot;

			StatusUpdate += DirectoryScannerDirectoryFinished;
		}

		private static void DirectoryScannerDirectoryFinished(object sender, WorkStatusArgs args)
		{
			//this is to do nothing if nobody subscribes to this event...
		}

		public void StartScan(string targetDir)
		{
			_root = targetDir;
			StartScan();
		}

		public void StartScan()
		{
			_fileInfo = new List<ProtoMedia>();
			StartWork();
		}

		protected override void DoWork(object args)
		{
			Logger.Info("Initial recursive call starting...");
			ScanDirectory(_root);

			Logger.Info("Recursive Scanning complete; firing the 'ScanningFinished' event...");
			WorkFinished.Invoke(this, new DirectoryFinishedArgs(_fileInfo, _root));
			Working = false;
		}

		private void ScanDirectory(string root)
		{
			Logger.Info(string.Format("Processing Directory [{0}]...", root));

			Logger.Debug("Getting/Processing sub-directories...");
			var currDir = new List<ProtoMedia>();

			try
			{
				var dirs = Directory.GetDirectories(root);

				foreach (var dir in dirs)
				{
					Logger.Debug(string.Format("Checking [_cancel] state:  currently set to [{0}].", Cancel));
					if (Cancel)
						return;

					ScanDirectory(dir);
				}

				

				Logger.Debug("Getting List of all files in current directory...");
				var files = Directory.GetFiles(root);
				foreach (var file in files)
				{
					Logger.Debug(string.Format("Checking [_cancel] state:  currently set to [{0}].", Cancel));
					if (Cancel)
						return;

					try
					{
						var curr = new ProtoMedia(file);
						Logger.Debug(string.Format("Adding a file to the list of files found; FileName: [{0}]; Extension: [{1}].",
						                           curr.FileName, curr.Extension));
						currDir.Add(curr);
						_fileInfo.Add(curr);
					}
					catch (Exception ex)
					{
						Logger.Error(ex,
						             string.Format("Unable to create a 'ProtoMedia' object for file [{0}];  File will be skipped.", file));
					}

				}

				if (dirs.Length == 0 && files.Length == 0)
				{
					Logger.Debug(string.Format(
						"Directory [{0}] is empty, it contains no sub-directories or files and will be deleted.", root));
					try
					{
						Directory.Delete(root);
					}
					catch (Exception ex)
					{
						Logger.Error(ex, string.Format("Unable to delete empty directory [{0}].", root));
					}
				}

				Logger.Debug(string.Format("Directory [{0}] has been processed...", root));
			} 
			catch(UnauthorizedAccessException uae)
			{
				Logger.Warn(string.Format("Unauthorized to access directory [{0}] and is being skipped...", root));
			}

			StatusUpdate.Invoke(this, new DirectoryFinishedArgs(currDir, root));
		}

	}

	public class DirectoryFinishedArgs : WorkFinishedArgs
	{
		public DirectoryFinishedArgs(IEnumerable<ProtoMedia> info, string dir)
			: base(null)
		{
			DirectoryScanned = dir;
			FileInformation = new List<ProtoMedia>();

			foreach (var proto in info)
				FileInformation.Add(proto);
		}

		public IList<ProtoMedia> FileInformation { get; private set; }
		public string DirectoryScanned { get; private set; }
	}

}